#include "dertos.h"
#include "uart2.h"

/* use precision */
#define DE_PRINTF_PRECISION

#define ZEROPAD     (1 << 0)    /* pad with zero */
#define SIGN        (1 << 1)    /* unsigned/signed long */
#define PLUS        (1 << 2)    /* show plus */
#define SPACE       (1 << 3)    /* space if plus */
#define LEFT        (1 << 4)    /* left justified */
#define SPECIAL     (1 << 5)    /* 0x */
#define LARGE       (1 << 6)    /* use 'ABCDEF' instead of 'abcdef' */

#ifdef DE_USING_DEVICE
/**
 * This function returns the device using in console.
 *
 * @return the device using in console or DE_NULL
 */
// de_device_t de_console_get_device(void)
// {
//     return _console_device;
// }
// RTM_EXPORT(de_console_get_device);

/**
 * This function will set a device as console device.
 * After set a device to console, all output of de_kprintf will be
 * redirected to this new device.
 *
 * @param name the name of new console device
 *
 * @return the old console device handler
 */
// de_device_t de_console_set_device(const char *name)
// {
//     de_device_t new, old;

//     /* save old device */
//     old = _console_device;

//     /* find new console device */
//     new = de_device_find(name);
//     if (new != DE_NULL)
//     {
//         if (_console_device != DE_NULL)
//         {
//             /* close old console device */
//             de_device_close(_console_device);
//         }

//         /* set new console device */
//         de_device_open(new, DE_DEVICE_OFLAG_RDWR | DE_DEVICE_FLAG_STREAM);
//         _console_device = new;
//     }

//     return old;
// }
// RTM_EXPORT(de_console_set_device);
#endif

void de_hw_console_output(const char *str)
{
    uart2_send_bytes(str, de_strlen(str));
}
// RTM_EXPORT(de_hw_console_output);

/**
 * This function will put string to the console.
 *
 * @param str the string output to the console.
 */
// void de_kputs(const char *str)
// {
//     if (!str) return;

// #ifdef DE_USING_DEVICE
//     if (_console_device == DE_NULL)
//     {
//         de_hw_console_output(str);
//     }
//     else
//     {
//         de_uint16_t old_flag = _console_device->open_flag;

//         _console_device->open_flag |= DE_DEVICE_FLAG_STREAM;
//         de_device_write(_console_device, 0, str, de_strlen(str));
//         _console_device->open_flag = old_flag;
//     }
// #else
//     de_hw_console_output(str);
// #endif
// }

/* private function */
#define isdigit(c)  ((unsigned)((c) - '0') < 10)

int skip_atoi(const char **s)
{
    register int i = 0;
    while (isdigit(**s))
        i = i * 10 + *((*s)++) - '0';

    return i;
}

/**
 * This function will return the length of a string, which terminate will
 * null character.
 *
 * @param s the string
 *
 * @return the length of string
 */
de_size_t de_strlen(const char *s)
{
    const char *sc;

    for (sc = s; *sc != '\0'; ++sc) /* nothing */
        ;

    return sc - s;
}

/**
 * This function will move memory content from source address to destination
 * address.
 *
 * @param dest the address of destination memory
 * @param src  the address of source memory
 * @param n the copied length
 *
 * @return the address of destination memory
 */
void *de_memmove(void *dest, const void *src, de_ubase_t n)
{
    char *tmp = (char *)dest, *s = (char *)src;

    if (s < tmp && tmp < s + n)
    {
        tmp += n;
        s += n;

        while (n--)
            *(--tmp) = *(--s);
    }
    else
    {
        while (n--)
            *tmp++ = *s++;
    }

    return dest;
}

#ifdef DE_PRINTF_PRECISION
static char *print_number(char *buf,
                          char *end,
                          long  num,
                          int   base,
                          int   s,
                          int   precision,
                          int   type)
#else
static char *print_number(char *buf,
                          char *end,
                          long  num,
                          int   base,
                          int   s,
                          int   type)
#endif
{
    char c, sign;
#ifdef DE_PRINTF_LONGLONG
    char tmp[32];
#else
    char tmp[16];
#endif
    const char *digits;
    static const char small_digits[] = "0123456789abcdef";
    static const char large_digits[] = "0123456789ABCDEF";
    register int i;
    register int size;

    size = s;

    digits = (type & LARGE) ? large_digits : small_digits;
    if (type & LEFT)
        type &= ~ZEROPAD;

    c = (type & ZEROPAD) ? '0' : ' ';

    /* get sign */
    sign = 0;
    if (type & SIGN)
    {
        if (num < 0)
        {
            sign = '-';
            num = -num;
        }
        else if (type & PLUS)
            sign = '+';
        else if (type & SPACE)
            sign = ' ';
    }

#ifdef DE_PRINTF_SPECIAL
    if (type & SPECIAL)
    {
        if (base == 16)
            size -= 2;
        else if (base == 8)
            size--;
    }
#endif

    i = 0;
    if (num == 0)
        tmp[i++] = '0';
    else
    {
        // while (num != 0)
        //     tmp[i++] = digits[divide(&num, base)];
    }

#ifdef DE_PRINTF_PRECISION
    if (i > precision)
        precision = i;
    size -= precision;
#else
    size -= i;
#endif

    if (!(type & (ZEROPAD | LEFT)))
    {
        if ((sign) && (size > 0))
            size--;

        while (size-- > 0)
        {
            if (buf <= end)
                *buf = ' ';
            ++ buf;
        }
    }

    if (sign)
    {
        if (buf <= end)
        {
            *buf = sign;
            -- size;
        }
        ++ buf;
    }

#ifdef DE_PRINTF_SPECIAL
    if (type & SPECIAL)
    {
        if (base == 8)
        {
            if (buf <= end)
                *buf = '0';
            ++ buf;
        }
        else if (base == 16)
        {
            if (buf <= end)
                *buf = '0';
            ++ buf;
            if (buf <= end)
            {
                *buf = type & LARGE ? 'X' : 'x';
            }
            ++ buf;
        }
    }
#endif

    /* no align to the left */
    if (!(type & LEFT))
    {
        while (size-- > 0)
        {
            if (buf <= end)
                *buf = c;
            ++ buf;
        }
    }

#ifdef DE_PRINTF_PRECISION
    while (i < precision--)
    {
        if (buf <= end)
            *buf = '0';
        ++ buf;
    }
#endif

    /* put number in the temporary buffer */
    while (i-- > 0)
    {
        if (buf <= end)
            *buf = tmp[i];
        ++ buf;
    }

    while (size-- > 0)
    {
        if (buf <= end)
            *buf = ' ';
        ++ buf;
    }

    return buf;
}

